import io
import json
import os
import re
import sys
import platform
import subprocess
import qrcode
import requests
from PIL import Image, ImageDraw, ImageFont
from datetime import datetime
import barcode
from barcode.writer import ImageWriter


def check_system_dependencies():
    """检查系统依赖是否安装"""
    missing_deps = []
    
    # 检查字体是否可用
    if not get_available_fonts():
        missing_deps.append("中文字体 (liberation-fonts, dejavu-sans-fonts)")
    
    # 检查PIL/Pillow
    try:
        from PIL import Image, ImageDraw, ImageFont
    except ImportError:
        missing_deps.append("Pillow")
    
    # 检查qrcode
    try:
        import qrcode
    except ImportError:
        missing_deps.append("qrcode")
    
    # 检查barcode
    try:
        import barcode
    except ImportError:
        missing_deps.append("python-barcode")
    
    if missing_deps:
        print(f"⚠️  缺少以下依赖: {', '.join(missing_deps)}")
        print("请运行以下命令安装:")
        if platform.system() == "Linux":
            if os.path.exists("/etc/redhat-release"):  # CentOS/RHEL
                print("sudo dnf install -y liberation-fonts dejavu-sans-fonts")
            elif os.path.exists("/etc/debian_version"):  # Debian/Ubuntu
                print("sudo apt-get install -y fonts-liberation fonts-dejavu-core")
        print("pip install Pillow qrcode[pil] python-barcode[images]")
        return False
    return True


def get_system_info():
    """获取系统信息"""
    system = platform.system()
    if system == "Linux":
        try:
            # 检查是否为CentOS/RHEL
            if os.path.exists("/etc/redhat-release"):
                with open("/etc/redhat-release", "r") as f:
                    return f"Linux-RHEL ({f.read().strip()})"
            elif os.path.exists("/etc/debian_version"):
                return "Linux-Debian"
            else:
                return "Linux-Unknown"
        except:
            return "Linux-Unknown"
    return system


def get_available_fonts():
    """获取系统可用的中文字体路径"""
    system = platform.system()
    fonts = []
    
    if system == "Windows":
        # Windows字体路径
        windows_fonts = [
            r"C:\Windows\Fonts\msyhbd.ttc",  # 微软雅黑 Bold
            r"C:\Windows\Fonts\msyhl.ttc",   # 微软雅黑 Light
            r"C:\Windows\Fonts\msyh.ttc",    # 微软雅黑
            r"C:\Windows\Fonts\simhei.ttf",  # 黑体
            r"C:\Windows\Fonts\simsun.ttc",  # 宋体
            r"C:\Windows\Fonts\arial.ttf",   # Arial
        ]
        fonts.extend([f for f in windows_fonts if os.path.exists(f)])
        
    elif system == "Linux":
        # Linux字体路径 - 优先使用Liberation和DejaVu字体
        linux_fonts = [
            # Liberation字体 (推荐用于CentOS)
            "/usr/share/fonts/liberation/LiberationSans-Bold.ttf",
            "/usr/share/fonts/liberation/LiberationSans-Regular.ttf",
            "/usr/share/fonts/liberation-fonts/LiberationSans-Bold.ttf",
            "/usr/share/fonts/liberation-fonts/LiberationSans-Regular.ttf",
            
            # DejaVu字体
            "/usr/share/fonts/dejavu/DejaVuSans-Bold.ttf",
            "/usr/share/fonts/dejavu/DejaVuSans.ttf",
            "/usr/share/fonts/dejavu-sans-fonts/DejaVuSans-Bold.ttf",
            "/usr/share/fonts/dejavu-sans-fonts/DejaVuSans.ttf",
            
            # 其他常见Linux字体
            "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf",
            "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf",
            "/usr/share/fonts/truetype/liberation/LiberationSans-Bold.ttf",
            "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
            
            # 中文字体
            "/usr/share/fonts/chinese/TrueType/uming.ttf",
            "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",
            "/usr/share/fonts/wqy-microhei/wqy-microhei.ttc",
            
            # 系统默认字体
            "/usr/share/fonts/TTF/arial.ttf",
            "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf",
        ]
        fonts.extend([f for f in linux_fonts if os.path.exists(f)])
        
    elif system == "Darwin":  # macOS
        macos_fonts = [
            "/System/Library/Fonts/PingFang.ttc",
            "/System/Library/Fonts/Helvetica.ttc",
            "/System/Library/Fonts/Arial.ttf",
        ]
        fonts.extend([f for f in macos_fonts if os.path.exists(f)])
    
    return fonts


def load_font_with_fallback(font_size, font_style="regular"):
    """
    加载字体，支持多种回退方案
    font_style: "bold", "light", "regular"
    """
    available_fonts = get_available_fonts()
    
    # 根据样式选择字体优先级
    if font_style == "bold":
        priority_keywords = ["Bold", "bold", "bd", "Black"]
    elif font_style == "light":
        priority_keywords = ["Light", "light", "Thin", "thin"]
    else:
        priority_keywords = ["Regular", "regular", "Normal", "normal", ""]
    
    # 按优先级排序字体
    sorted_fonts = []
    for keyword in priority_keywords:
        for font_path in available_fonts:
            if keyword in os.path.basename(font_path):
                sorted_fonts.append(font_path)
    
    # 添加剩余字体
    for font_path in available_fonts:
        if font_path not in sorted_fonts:
            sorted_fonts.append(font_path)
    
    # 尝试加载字体
    for font_path in sorted_fonts:
        try:
            font = ImageFont.truetype(font_path, size=font_size)
            print(f"✅ 成功加载字体: {os.path.basename(font_path)}")
            return font
        except Exception as e:
            print(f"⚠️  字体加载失败 {os.path.basename(font_path)}: {e}")
            continue
    
    # 最后的回退方案
    try:
        # 尝试使用系统默认字体
        if hasattr(ImageFont, 'load_default'):
            try:
                font = ImageFont.load_default(size=font_size)
                print(f"✅ 使用系统默认字体 (size={font_size})")
                return font
            except:
                font = ImageFont.load_default()
                print("✅ 使用系统默认字体 (默认大小)")
                return font
        else:
            font = ImageFont.load_default()
            print("✅ 使用系统默认字体")
            return font
    except Exception as e:
        print(f"❌ 所有字体加载失败: {e}")
        return None


def get_date():
    # 获取当前日期和时间
    now = datetime.now()

    # 获取今天的最后一分钟
    last_minute_of_today = now.replace(hour=23, minute=59, second=0, microsecond=0)

    # 格式化输出
    formatted_time = last_minute_of_today.strftime('%Y/%m/%d %H:%M')
    return formatted_time

def create_image_with_text(text, width, height, font_size, font_style, img_path, color):
    """
    创建带文字的图片，优化了字体加载逻辑
    font_style: "bold", "light", "regular"
    """
    try:
        # 创建一个背景图片
        image = Image.new('RGB', (width, height), color=color)
        draw = ImageDraw.Draw(image)

        # 加载字体
        font = load_font_with_fallback(font_size, font_style)
        
        # 如果字体加载失败，创建空白图片
        if font is None:
            print(f"⚠️  字体加载失败，创建空白图片: {img_path}")
            image.save(img_path)
            return image
        
        # 确保文本是字符串类型
        if not isinstance(text, str):
            text = str(text)
        
        # 文字的宽度和高度 - 兼容新旧版本Pillow
        try:
            # 新版本Pillow使用textbbox
            bbox = draw.textbbox((0, 0), text, font=font)
            text_width = bbox[2] - bbox[0]
            text_height = bbox[3] - bbox[1]
        except AttributeError:
            # 旧版本Pillow使用textsize
            try:
                text_width, text_height = draw.textsize(text, font=font)
            except:
                # 如果textsize也不可用，使用估算
                text_width = len(text) * font_size * 0.6
                text_height = font_size

        # 计算文字的位置，使其居中
        x = max(0, (width - text_width) / 2)
        y = max(0, (height - text_height) / 2)

        # 将文字画到图片上
        draw.text((x, y), text, font=font, fill='black')
        
        # 保存图片
        image.save(img_path)
        print(f"✅ 图片创建成功: {img_path}")
        return image
        
    except Exception as e:
        print(f"❌ 创建图片失败 {img_path}: {e}")
        # 创建空白图片作为备选
        try:
            blank_image = Image.new('RGB', (width, height), color=color)
            blank_image.save(img_path)
            return blank_image
        except Exception as e2:
            print(f"❌ 创建空白图片也失败: {e2}")
            raise e


# 使用示例
def get_png_title(text):
    color = (250, 250, 250)
    img_path = "title.png"
    text = text
    width = 1440
    height = 90
    font_size = 61  # 自定义字体大小
    font_style = "bold"  # 使用粗体
    create_image_with_text(text, width, height, font_size, font_style, img_path, color)

def get_png_date(text):
    color = (250, 250, 250)
    img_path = "date.png"
    text = text
    width = 350
    height = 52
    font_size = 38  # 自定义字体大小
    font_style = "light"  # 使用细体
    create_image_with_text(text, width, height, font_size, font_style, img_path, color)

def get_png_code(text):
    color = "white"
    img_path = "code.png"
    text = text
    width = 550
    height = 90
    font_size = 65  # 自定义字体大小
    font_style = "regular"  # 使用常规字体
    create_image_with_text(text, width, height, font_size, font_style, img_path, color)

def get_png_notes(text):
    color = (250, 250, 250)
    img_path = "notes.png"
    text = text
    width = 600
    height = 70
    font_size = 50  # 自定义字体大小
    font_style = "bold"  # 使用粗体
    create_image_with_text(text, width, height, font_size, font_style, img_path, color)


def get_png_qrcode(code_str):
    """生成二维码图片，添加错误处理"""
    try:
        qr = qrcode.QRCode(
            version=1,  # 版本号，控制二维码的大小（1到40），1是最小的
            error_correction=qrcode.constants.ERROR_CORRECT_L,  # 容错率，L为大约7%或更少的错误会被纠正
            box_size=8,  # 每个"盒"的像素数
            border=0,  # 边框宽度，单位是box_size
        )

        # 添加数据到二维码对象中
        qr.add_data(str(code_str))
        qr.make(fit=True)  # 根据提供的数据生成二维码

        # 创建图像
        img = qr.make_image(fill_color="black", back_color="white")

        # 如果需要设置特定的宽度和高度，可以使用Pillow库来调整图像大小
        width, height = 490, 490  # 指定的宽度和高度
        
        # 兼容新旧版本Pillow
        try:
            # 新版本Pillow使用LANCZOS
            img = img.resize((width, height), Image.LANCZOS)
        except AttributeError:
            try:
                # 旧版本Pillow使用ANTIALIAS
                img = img.resize((width, height), Image.ANTIALIAS)
            except AttributeError:
                # 更旧版本使用BICUBIC
                img = img.resize((width, height), Image.BICUBIC)

        # 保存图像到文件
        img.save("qrcode.png")
        print("✅ 二维码生成成功: qrcode.png")
        
    except Exception as e:
        print(f"❌ 二维码生成失败: {e}")
        # 创建空白图片作为备选
        try:
            blank_img = Image.new('RGB', (490, 490), color='white')
            blank_img.save("qrcode.png")
        except Exception as e2:
            print(f"❌ 创建空白二维码图片失败: {e2}")
            raise e



def get_png_barcode(text):
    """生成条形码图片，添加错误处理"""
    try:
        # 创建Code128条形码对象
        code128 = barcode.get('code128', str(text), writer=ImageWriter())

        # 设置条形码的属性以隐藏文字和调整大小
        options = {
            'text_distance': 0,  # 不显示文字
            'font_size': 1,  # 最小字体大小，避免为0导致错误
            'module_width': 0.4,  # 条形码宽度
            'module_height': 10.0,  # 条形码高度
            'write_text': False,  # 不显示文字
        }
        # 生成条形码图像
        barcode_image = code128.render(options)
        # 旋转条形码图像90度
        rotated_image = barcode_image.rotate(90, expand=True)

        # 保存旋转后的图像
        rotated_image.save("barcode.png")
        print("✅ 条形码生成成功: barcode.png")
        
    except Exception as e:
        print(f"❌ 条形码生成失败: {e}")
        # 创建空白图片作为备选
        try:
            blank_img = Image.new('RGB', (100, 400), color='white')
            blank_img.save("barcode.png")
        except Exception as e2:
            print(f"❌ 创建空白条形码图片失败: {e2}")
            raise e


def get_title_code(text):
    """提取标题和券码，添加错误处理"""
    try:
        if not isinstance(text, str):
            text = str(text)
            
        pattern = r"「(.*?)」券码已恢复，新券码为(\d+)。"
        # 使用正则表达式搜索
        match = re.search(pattern, text)

        if match:
            # 提取匹配的组
            item_name = match.group(1)  # 提取商品名称
            new_code1 = match.group(2)  # 提取券码
            new_code2 = f"{new_code1[:4]} {new_code1[4:8]} {new_code1[8:]}"
        else:
            item_name = "未知商品"
            new_code1 = "000000000000"
            new_code2 = "0000 0000 0000"
        return item_name, new_code1, new_code2
    except Exception as e:
        print(f"❌ 提取标题和券码失败: {e}")
        return "未知商品", "000000000000", "0000 0000 0000"



def del_png(image_path):
    """删除临时图片文件"""
    try:
        if os.path.exists(image_path):
            # 删除文件
            os.remove(image_path)
            print(f"🗑️  文件 {image_path} 已被删除。")
        else:
            print(f"⚠️  文件 {image_path} 不存在。")
    except Exception as e:
        print(f"❌ 删除文件失败 {image_path}: {e}")


def get_png(barcode_text):
    """合成最终的券码图片"""
    try:
        # 打开各个组件图片
        image_files = {
            "title.png": (0, 319),      # 标题
            "date.png": (650, 416),     # 日期
            "code.png": (120, 680),     # 券码
            "qrcode.png": (406, 868),   # 二维码
            "barcode.png": (949, 838),  # 条形码
            "notes.png": (10, 3000),    # 备注
        }
        
        # 检查模板图片是否存在
        template_path = "config/mt样图.jpg"
        if not os.path.exists(template_path):
            template_path = "config\\mt样图.jpg"  # Windows路径
            if not os.path.exists(template_path):
                raise FileNotFoundError(f"模板图片不存在: {template_path}")
        
        # 打开模板图片
        image = Image.open(template_path)
        
        # 逐个粘贴组件图片
        for img_file, (x, y) in image_files.items():
            if os.path.exists(img_file):
                try:
                    component_img = Image.open(img_file)
                    image.paste(component_img, (x, y), None)
                    print(f"✅ 粘贴组件成功: {img_file}")
                except Exception as e:
                    print(f"⚠️  粘贴组件失败 {img_file}: {e}")
            else:
                print(f"⚠️  组件图片不存在: {img_file}")

        # 保存最终图片
        output_path = f"{barcode_text}.jpg"
        image.save(output_path)
        print(f"✅ 最终图片生成成功: {output_path}")
        
        # 清理临时文件
        for img_file in image_files.keys():
            del_png(img_file)
        
        return output_path
        
    except Exception as e:
        print(f"❌ 合成图片失败: {e}")
        # 清理临时文件
        for img_file in ["title.png", "date.png", "code.png", "qrcode.png", "barcode.png", "notes.png"]:
            del_png(img_file)
        raise e



def main(title, barcode_text, code, notes):
    """主函数，生成券码图片"""
    try:
        print(f"🎫 开始生成券码图片...")
        print(f"系统信息: {get_system_info()}")
        
        # 检查系统依赖
        if not check_system_dependencies():
            print("❌ 系统依赖检查失败，但继续尝试生成图片...")
        
        # 生成各个组件
        title_text = str(title) if title else "团购券"
        code_text = str(code) if code else "0000 0000 0000"
        notes_text = str(notes) if notes else ""
        
        get_png_title(title_text)
        date_text = get_date()
        get_png_date(date_text)
        get_png_code(code_text)
        get_png_qrcode(barcode_text)
        get_png_barcode(barcode_text)
        get_png_notes(notes_text)
        
        # 合成最终图片
        result_path = get_png(barcode_text)
        print(f"🎉 券码图片生成完成: {result_path}")
        return result_path
        
    except Exception as e:
        print(f"❌ 生成券码图片失败: {e}")
        raise e


def format_voucher_code(voucher_code):
    """格式化券码，支持任意字符序列"""
    try:
        # 确保是字符串
        if not isinstance(voucher_code, str):
            voucher_code = str(voucher_code)
        
        # 清理前后空白
        voucher_code = voucher_code.strip()
        
        # 如果是纯数字且长度合适，尝试格式化为分组显示
        if voucher_code.isdigit() and len(voucher_code) >= 8:
            # 对于数字券码，每4位一组插入空格
            if len(voucher_code) == 12:
                return f"{voucher_code[:4]} {voucher_code[4:8]} {voucher_code[8:12]}"
            elif len(voucher_code) == 11:
                return f"{voucher_code[:4]} {voucher_code[4:7]} {voucher_code[7:11]}"
            elif len(voucher_code) == 10:
                return f"{voucher_code[:3]} {voucher_code[3:6]} {voucher_code[6:10]}"
            elif len(voucher_code) >= 8:
                # 对于其他长度的数字，尝试均匀分组
                mid = len(voucher_code) // 2
                return f"{voucher_code[:mid]} {voucher_code[mid:]}"
        
        # 对于非数字或较短的字符串，直接返回
        return voucher_code if voucher_code else "无效券码"
    except Exception as e:
        print(f"❌ 格式化券码失败: {e}")
        return voucher_code if voucher_code else "无效券码"


def extract_voucher_code(text):
    """提取券码，接受任意字符作为券码"""
    try:
        # 确保输入是字符串类型
        if text is None:
            return None
            
        # 安全地处理字符串编码
        if isinstance(text, bytes):
            try:
                text = text.decode('utf-8', errors='ignore')
            except:
                return None
        elif not isinstance(text, str):
            try:
                text = str(text)
            except:
                return None
        
        # 清理前后空白字符
        text = text.strip()
        
        # 如果有内容就返回，不再限制为12位数字
        if text:
            return text
        
        return None  # 空字符串时返回None
    except Exception as e:
        print(f"❌ 提取券码时发生错误: {e}")
        return None


def gm_main(message):
    """生成券码图片的主函数，添加错误处理"""
    try:
        print(f"🚀 开始处理券码生成请求...")
        print(f"系统环境: {get_system_info()}")
        
        # 安全地处理输入消息
        if message is None:
            raise ValueError("输入消息不能为空")
            
        # 确保消息是字符串类型
        if isinstance(message, bytes):
            try:
                message = message.decode('utf-8', errors='ignore')
            except:
                raise ValueError("无法解码输入消息")
        elif not isinstance(message, str):
            try:
                message = str(message)
            except:
                raise ValueError("无法转换输入消息为字符串")
        
        # 提取券码
        barcode_text = extract_voucher_code(message)
        if barcode_text is None:
            raise ValueError(f"无法从消息中提取券码: {message[:100]}...")  # 只显示前100个字符
            
        # 格式化券码
        code = format_voucher_code(barcode_text)
        
        # 生成图片
        image_path = main("团购券", barcode_text, code, "")
        print(f"🎉 券码图片生成成功: {image_path}")
        return image_path
        
    except Exception as e:
        print(f"❌ 生成券码图片失败: {e}")
        print(f"错误类型: {type(e).__name__}")
        import traceback
        print(f"详细错误信息:\n{traceback.format_exc()}")
        raise e


# 添加测试函数
def test_font_loading():
    """测试字体加载功能"""
    print("🧪 测试字体加载功能...")
    print(f"系统信息: {get_system_info()}")
    
    available_fonts = get_available_fonts()
    print(f"可用字体数量: {len(available_fonts)}")
    
    for i, font_path in enumerate(available_fonts[:5]):  # 只显示前5个
        print(f"  {i+1}. {font_path}")
    
    if available_fonts:
        print("✅ 字体检测正常")
        
        # 测试加载不同样式的字体
        for style in ["regular", "bold", "light"]:
            font = load_font_with_fallback(24, style)
            if font:
                print(f"✅ {style} 字体加载成功")
            else:
                print(f"❌ {style} 字体加载失败")
    else:
        print("❌ 未找到可用字体")
    
    return len(available_fonts) > 0


if __name__ == "__main__":
    # 运行字体测试
    test_font_loading()
    
    # 测试券码生成
    test_message = "「测试商品」券码已恢复，新券码为123456789012。"
    try:
        result = gm_main(test_message)
        print(f"测试成功: {result}")
    except Exception as e:
        print(f"测试失败: {e}")

